package biopepa;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;


public class DiscreteTrans {
	public String discreteName;
	public String discreteNameWith;
	public String guard;
	public String reset;
	public String rate;
	public NewLocation location;
	public int counter1;
	public int counter2;
	public boolean isContinuous;
	public boolean isContinuous2;
	public boolean isReagOrProd;	
	public boolean isDisplacement;
	public BiopepaModel model;
	
	public DiscreteTrans(Automaton auto, NewLocation newLocation, NewSpecies species , ActionEnabled action , BiopepaModel newModel){
		model = newModel;
		isContinuous = species.isContinuous;
		isDisplacement = false;
		location = newLocation;
		//Set name		
		discreteName = action.actionEnabledName;
		discreteNameWith = action.actionEnabledName + "." + location.locationName;
		//System.out.println(discreteName + " " + discreteNameWith);
		isContinuous2 = isContinuous();
		isReagOrProd = false;
		
		if(isContinuous2 == false){
			//Set is reagent or product
			if(action.operator == 1 || action.operator == 2 ||  action.operator == 6 || action.operator == 7 ){
				isReagOrProd = true;
			}
			//Set guard
			NewParameter parameter;
			if(action.operator == 1 ||  action.operator == 6 ){		
				if(species.isContinuous == false){
					if(model.hasLocations == true){
						parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g", action.stoichiometry + "*" + location.stepSizeVariableD);
					}
					else{
						parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g", action.stoichiometry + "*" + location.stepSizeVariableD);
					}					
				}
				else{
					if(model.hasLocations == true){
						parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g", action.stoichiometry + "*" + location.stepSizeVariableC);
					}
					else{
						parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g", action.stoichiometry + "*" + location.stepSizeVariableC);
					}
				}
				parameter.isSpecParam = true;
				model.parameterObjects.put(parameter.parameterName, parameter);
				guard = auto.getAutoName() + ">=" + parameter.parameterName;
			}
			else if(action.operator == 2 || action.operator == 7){
				String result;
				if(model.hasOneLocation == false){
					int num;
					int upper = species.locationsAccessible.get(newLocation.locationName).upper;
					if(species.isContinuous == false){
						num = upper - action.stoichiometry;
						result = num + "*" + location.stepSizeVariableD ;
					}
					else{
						result = upper + "*" + location.stepSizeVariableD + "-" +  action.stoichiometry + "*" + location.stepSizeVariableC ;
					}
				}
				else{
					int num;
					if(species.isContinuous == false){
						num = species.speciesUpper - action.stoichiometry;
						result = num + "*" + location.stepSizeVariableD ;
					}
					else{
						result = species.speciesUpper + "*" + location.stepSizeVariableD + "-" +  action.stoichiometry + "*" + location.stepSizeVariableC ;
					}
				}
				NewParameter parameter3;
				if(species.isContinuous == false){
					if(model.hasLocations == true){
						parameter3 = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g",   result );
					}
					else{
						parameter3 = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g",   result );
					}					
				}
				else{
					if(model.hasLocations == true){
						parameter3 = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g",   result );
					}
					else{
						parameter3 = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g",   result );
					}				
				}
				parameter3.isSpecParam = true;
				model.parameterObjects.put(parameter3.parameterName, parameter3);
				guard = auto.getAutoName() + "<=" + parameter3.parameterName;
			}
			else if(action.operator == 3 || action.operator == 4 || action.operator == 5){}
			
			//Set reset
			NewParameter parameter2;
			if(species.isContinuous==false){
				if(model.hasLocations == true){
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".r", action.stoichiometry + "*" + location.stepSizeVariableD);
				}
				else{
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".r", action.stoichiometry + "*" + location.stepSizeVariableD);
				}
			}
			else{
				if(model.hasLocations == true){
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".r", action.stoichiometry + "*" + location.stepSizeVariableC);
				}
				else{
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".r", action.stoichiometry + "*" + location.stepSizeVariableC);
				}
				
			}
			if(action.operator == 1){
				parameter2.isSpecParam = true;
				model.parameterObjects.put(parameter2.parameterName, parameter2);
				reset = auto.getAutoName() + "-=" +parameter2.parameterName;
			}
			else if(action.operator == 2 ){
				parameter2.isSpecParam = true;
				model.parameterObjects.put(parameter2.parameterName, parameter2);
				reset = auto.getAutoName() + "+=" + parameter2.parameterName;
			}
			else{
				
			}
		}
		else{
			//Set is reagent or product
			if(action.operator == 1 || action.operator == 2 ||  action.operator == 6 || action.operator == 7){
				isReagOrProd = true;
			}
			//Set guard
			NewParameter parameter;
			if(species.isContinuous == false){
				if(model.hasLocations == true ){
					parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g", action.stoichiometry + "*" + location.stepSizeVariableD);
				}
				else{
					parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g", action.stoichiometry + "*" + location.stepSizeVariableD);
				}
			}
			else{
				if(model.hasLocations == true ){
					parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g", action.stoichiometry + "*" + location.stepSizeVariableC);
				}
				else{
					parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g", action.stoichiometry + "*" + location.stepSizeVariableC);
				}
			}
			if(action.operator == 1 ||  action.operator == 6 || action.operator == 7){
				parameter.isSpecParam = true;
				model.parameterObjects.put(parameter.parameterName, parameter);
				guard = auto.getAutoName() + ">=" + parameter.parameterName;
			}
			else if(action.operator == 2 || action.operator == 7){
				String result;
				int upper = species.locationsAccessible.get(newLocation.locationName).upper;
				if(model.hasOneLocation == false){
					if(species.isContinuous == false){
						int num;
						num = upper - action.stoichiometry;
						result = num + "*" + location.stepSizeVariableD ;
					}
					else{
						result = upper + "*" + location.stepSizeVariableD + "-" + action.stoichiometry + "*" +  location.stepSizeVariableC ;
					}
				}
				else{
					if(species.isContinuous == false){
						result = "(" + species.speciesUpper + "-" + action.stoichiometry + ")*" + location.stepSizeVariableD ;
					}
					else{
						result = species.speciesUpper + "*" + location.stepSizeVariableD + "-" + action.stoichiometry + "*" +  location.stepSizeVariableC ;
					}
				}
				NewParameter parameter3 = new NewParameter(species.speciesName + "_" + action.actionEnabledName + ".g",   result );
				parameter3.isSpecParam = true;
				//model.parameterObjects.put(parameter3.parameterName, parameter3);
				//guard = auto.getAutoName() + "<=" + parameter3.parameterName;
			}
			else if(action.operator == 3 || action.operator == 4 || action.operator == 5){}
			
			//Set reset
			NewParameter parameter2;
			if(species.isContinuous == false){
				if(model.hasLocations == true){
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".r", action.stoichiometry + "*" + location.stepSizeVariableD);
				}
				else{
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".r", action.stoichiometry + "*" + location.stepSizeVariableD);
				}
			}
			else{
				if(model.hasLocations == true){
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".r", action.stoichiometry + "*" + location.stepSizeVariableC);
				}
				else{
					parameter2 = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".r", action.stoichiometry + "*" + location.stepSizeVariableC);
				}
			}
			if(action.operator == 1){
				parameter.isSpecParam = true;
				model.parameterObjects.put(parameter2.parameterName, parameter2);
				reset = auto.getAutoName() + "-=" +parameter2.parameterName;
			}
			else if(action.operator == 2 ){
				parameter2.isSpecParam = true;
				model.parameterObjects.put(parameter2.parameterName, parameter2);
				reset = auto.getAutoName() + "+=" + parameter2.parameterName;
			}
			else{}
		}
		}
		
		
		public DiscreteTrans(Automaton auto, Boolean isExing, NewLocation newLocation, NewSpecies species , ActionEnabled action , BiopepaModel newModel){
			model = newModel;
			isContinuous2 = species.isContinuous;
			isDisplacement = false;
			//System.out.println("cons " + auto.getAutoName() + " e " + action.actionEnabledName + " in " + newLocation.locationName);
			location = newLocation;
			//Set name		
//			discreteName = action.actionEnabledName + "." + location.locationName;
//			discreteNameWith = action.actionEnabledName + "(" + auto.getAutoName() + action.operator + action.stoichiometry + ")";
			discreteName = action.actionEnabledName;
			discreteNameWith = action.actionEnabledName + "." + location.locationName;
			//System.out.println(discreteName + " " + discreteNameWith);
			isContinuous2 = isContinuous();
			isReagOrProd = false;
			
			if(isContinuous2 == false){
				//Set is reagent or product
				if(isExing==true){
					isReagOrProd = true;
				}
				//Set guard
				if(isExing==true){
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g", action.stoichiometry + "*" + location.stepSizeVariableD);
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					guard = auto.getAutoName() + ">=" + parameter.parameterName;
				}
				else{
					int result = species.speciesUpper - action.stoichiometry;
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".g",   result +  "*" + location.stepSizeVariableD );
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					guard = auto.getAutoName() + "<=" + parameter.parameterName;
				}
				
				//Set reset
				if(isExing==true){
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".r", action.stoichiometry + "*" + location.stepSizeVariableD);
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					reset = auto.getAutoName() + "-=" +parameter.parameterName;
				}
				else{
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + "." + location.locationName + ".r", action.stoichiometry + "*" + location.stepSizeVariableD);
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					reset = auto.getAutoName() + "+=" + parameter.parameterName;
				}
			}
			else{
				//Set is reagent or product
				if(isExing==true ){
					isReagOrProd = true;
				}
				//Set guard
				if(isExing==true){
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g", action.stoichiometry + "*" + location.stepSizeVariableC);
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					guard = auto.getAutoName() + ">=" + parameter.parameterName;
				}
				else{
					int result = species.speciesUpper - action.stoichiometry;
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".g",   result +  "*" + location.stepSizeVariableC );
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					guard = auto.getAutoName() + "<=" + parameter.parameterName;
				}
				
				//Set reset
				if(isExing==true){
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".r", action.stoichiometry + "*" + location.stepSizeVariableC);
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					reset = auto.getAutoName() + "-=" +parameter.parameterName;
				}
				else{
					NewParameter parameter = new NewParameter(species.speciesName + "." + action.actionEnabledName + ".r", action.stoichiometry + "*" + location.stepSizeVariableC);
					parameter.isSpecParam = true;
					model.parameterObjects.put(parameter.parameterName, parameter);
					reset = auto.getAutoName() + "+=" + parameter.parameterName;
				}
			}
		
		
		
		//Set rate
		NewLaw law;
		law = model.lawObjects.get(action.actionEnabledName);
		counter1 = 0;
		counter2 = 0;
	}
	
	public DiscreteTrans(String name){
		discreteName = name ;
		isContinuous = false;
	}
	
	public DiscreteTrans(String name, NewLaw law){
		discreteName = name ;
		rate = law.lawExpression;
		isContinuous = false;
	}
	
	public DiscreteTrans(NewLaw law){
		discreteName = law.lawOf;
		rate = law.lawExpression;
		isContinuous = false;
	}
	
	public boolean isContinuous(){ //With respect to the whole system
		boolean bool;
		bool=true;

			Iterator iterator1 = model.speciesList.keySet().iterator();  		   
			while (iterator1.hasNext()) {  
				 String key = iterator1.next().toString(); 
				 NewSpecies spec = model.speciesList.get(key); 
				 HashMap< String , ActionEnabled > acts = spec.getActionsEnabledObjects();
				 if(acts.containsKey(this.discreteName)){
					 //System.out.println("Azione " + this.discreteName + " species " + spec.speciesName);
					 if(acts.get(this.discreteName).operator == 1 || acts.get(this.discreteName).operator == 2 || acts.get(this.discreteName).operator == 6 || acts.get(this.discreteName).operator == 7 ){
						 //System.out.println("operatore giusto");
						 if(spec.isContinuous == false){
								bool = false;
							 }
					 }
					 
				 }
				
			}
		
		
		return bool;
	}

}
